package emby.util;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;

import javax.script.ScriptException;


/**
 * Java language improvements inspired by Python.
 * Static import to use.
 *
 *  Sources for some methods and algorithms:<br>
 * <a href=http://www.vogella.de/articles/JavaAlgorithmsQuicksort/article.html>Quicksort </a><br>
 * <a href =http://introcs.cs.princeton.edu/java/23recursion/BinaryGCD.java.html>Binary GCD </a><br>
 * <a href =http://www.javapractices.com/topic/TopicAction.do?Id=42>Text to File IO </a>
 *
 * <BR><BR>
 * @author Justin and some websites. See above for sources
 * @date 9/6/2011
 *
 */

public class L {

	public final static double _PI = 3.14159265358979323846;
	public final static double _E = 2.71828182845904523536;
	public final static double _PIOVER180 = 0.017453292519943295769;
	public final static double _180OVERPI = 57.2957795130823208768;
	public final static float toDeg = 57.2957795130823208768f;
	public final static float toRad = 0.017453292519943295769f;

	//EVAL!
	private static javax.script.ScriptEngineManager manager;
    private static javax.script.ScriptEngine engine;
    /**
     * Eval function using JavaScript. The context of the engine can be reset by calling resetEvalEngine()
     * @param s Script to be evaluated
     * @return the result
     */
    public static Object eval(String s){
    	if(manager==null || engine==null){
    		resetEvalEngine();
    	}

	    try {
			return engine.eval(s);
		} catch (ScriptException e) {
			e.printStackTrace();
			return null;
		}
	}
    /**
     * Resets the eval engine. (Clears all variables, completely fresh restart, etc)
     */
    public static void resetEvalEngine(){
    	manager = new javax.script.ScriptEngineManager();
        engine = manager.getEngineByName("js");
    }

	/*
	 * MISCELLANEOUS FUNCTIONS
	 */
	public static void println(Object... o){
		print(o);
		System.out.print("\n");
	}
	public static void print(Object... o){
		for(int i = 0; i<o.length;i++){
			System.out.print(o[i].toString());
		}
	}
	public static void printf(String s, Object... o){
		System.out.printf(s, o);
	}
	public static void errprint(Object... o){
		for(int i = 0; i<o.length;i++){
			System.err.print(o[i].toString());
		}
	}
	public static void errprintln(Object... o){
		errprint(o);
		System.err.println();
	}

	public static <E> void printArray(ArrayList<E> o){
		print("{");
		for(int i = 0; i<o.size()-1;i++){
			print(o.get(i).toString()+",");
		}
		print(o.get(o.size()-1).toString()+"}");
	}
	public static <E> void printlnArray(ArrayList<E> o){
		print("{");
		for(int i = 0; i<o.size()-1;i++){
			print(o.get(i).toString()+",");
		}
		print(o.get(o.size()-1).toString()+"}\n");
	}
	public static <E> void printArray(E[] o){
		printArray(ArrayList(o));
	}
	public static <E> void printlnArray(E[] o){
		printlnArray(ArrayList(o));
	}
	public static  void printlnArray(int[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}\n");
	}
	public static  void printArray(int[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}");
	}
	public static  void printlnArray(double[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}\n");
	}
	public static  void printArray(double[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}");
	}
	public static  void printlnArray(float[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}\n");
	}
	public static  void printArray(float[] o){
		print("{");
		for(int i = 0; i<o.length-1;i++){
			print(o[i]+",");
		}
		print(o[o.length-1]+"}");
	}

	public static Class<? extends Object> type(Object o){
		return o.getClass();
	}

	/**
	 * Returns the system time in milliseconds
	 * @return
	 */
	public static long systemTime(){
		return System.currentTimeMillis();
	}

	/**
	 * Sleeps the current thread
	 * @param milliseconds time to sleep for in ms
	 */
	public static void sleep(int milliseconds){
		try{Thread.sleep(milliseconds);
		}
		catch(InterruptedException e){e.printStackTrace();}
	}

	private static long previousTime = 0;//used by the timer
	/**
	 * Starts the internal timer. Timer can be stopped by calling timerStop() or time can be obtained without stopping by calling timerElapsed()
	 * <BR>
	 */
	public static void timerStart(){
		timerStop();
		previousTime = System.currentTimeMillis();
	}
	/**
	 * Returns time elapsed since timer was started and stops the timer. Will return -1 if timer was already stopped.
	 * <BR>
	 * @return time elapsed or -1 if timer is already stopped.
	 */
	public static long timerStop(){
		if(previousTime !=0){
		long time = System.currentTimeMillis()-previousTime;
		previousTime = 0;
		return time;}
		else{return -1;}
	}
	/**
	 * Returns time elapsed since timer was started without stopping the timer. Will return -1 if timer was stopped.
	 * <BR>
	 * @return time elapsed or -1 if timer is stopped.
	 */
	public static long timerElapsed(){
		if(previousTime !=0)
			return System.currentTimeMillis()-previousTime;
		else
			return -1;
	}


	/*
	 * TYPECASTING FUNCTIONS
	 */

	/**
	 * Converts a number to a string
	 * @param n
	 * @return
	 */
	public static String String(java.lang.Number n){
		return String.valueOf(n);
	}
	/**
	 * Converts an object to a string. Simply calls toString()
	 * @param o
	 * @return string representation of the object
	 */
	public static String String(Object o){
		return o.toString();
	}

	/**
	 * ParseFloat
	 * @param cheese string to be converted to a float
	 * @return
	 */
	public static float Float(String cheese){
		return Float.parseFloat(cheese);
	}
	/**
	 * Converts a number to float
	 * <BR>
	 * Calls floatValue()
	 * @param n number to convert to float
	 * @return
	 */
	public static float Float(java.lang.Number n){
		return n.floatValue();
	}

	/**
	 * ParseDouble
	 * @param cheese string to be converted to a double
	 * @return
	 */
	public static double Double(String cheese){
		return Double.parseDouble(cheese);
	}
	/**
	 * Converts a number to double
	 * <BR>
	 * Calls doubleValue()
	 * @param n number to convert to double
	 * @return
	 */
	public static double Double(java.lang.Number n){
		return n.doubleValue();
	}

	/**
	 * ParseInt
	 * <BR>
	 * If a double is parsed, it will be rounded??
	 * @param cheese string to be converted to an integer
	 * @return
	 */
	public static int Int(String cheese){
		try{
		return Integer.parseInt(cheese);
		}catch(NumberFormatException e){
			return (int)Double.parseDouble(cheese);
		}
	}
	/**
	 * Converts a number to int
	 * <BR>
	 * Calls intValue()
	 * @param n number to convert to int
	 * @return
	 */
	public static int Int(java.lang.Number n){
		return n.intValue();
	}

	/**
	 * ParseByte
	 * <BR>
	 * If a double is parsed, it will be rounded ??
	 * @param cheese string to be converted to a byte
	 * @return
	 */
	public static byte Byte(String cheese){
		try{
		return Byte.parseByte(cheese);}
		catch(NumberFormatException e){
			return (byte)Double.parseDouble(cheese);
		}
	}
	/**
	 * Converts a number to byte
	 * @param n number to convert to char
	 * @return
	 */
	public static byte Byte(java.lang.Number n){
		return n.byteValue();
	}


	/**
	 * Casts an object to a boolean. If object is null, returns false. If not, returns true.
	 * @param o
	 * @return true if not null,  false if null
	 */
	public static boolean bool(Object o){
		if(o==null)return false;
		else return true;
	}
	/**
	 * Casts a number into a boolean. If a number is nonzero, returns true. If zero, returns false
	 * @param n
	 * @return true if nonzero, false if zero
	 */
	public static boolean bool(Number n){
		if(n.doubleValue()==0)return false;
		else return true;
	}

	//list typecasting

	/**
	 * Casts an ArrayList of numbers to an integer array
	 * @param nums
	 * @return
	 */
	public static int[] intArray(ArrayList<Number> nums){
		int[] ints = new int[nums.size()];
		for(int i = 0; i<nums.size();i++){
			ints[i] = nums.get(i).intValue();
		}
		return ints;
	}
	/**
	 * Casts an integer array into an arraylist of numbers
	 * @param array
	 * @return
	 */
	public static ArrayList<Number> intArrayList(int... array){
		ArrayList<Number> nums = new ArrayList<Number>(0);
		for(int i = 0; i<array.length;i++){
			nums.add(i,array[i]);
		}
		return nums;
	}

	/**
	 * Casts an ArrayList of numbers to a double array
	 * @param nums
	 * @return
	 */
	public static double[] doubleArray(ArrayList<Number> nums){
		double[] dbls = new double[nums.size()];
		for(int i = 0; i<nums.size();i++){
			dbls[i] = nums.get(i).doubleValue();
		}
		return dbls;
	}
	/**
	 * Casts a double array into an arraylist of numbers
	 * @param array
	 * @return
	 */
	public static ArrayList<Number> doubleArrayList(double... array){
		ArrayList<Number> nums = new ArrayList<Number>(0);
		for(int i = 0; i<array.length;i++){
			nums.add(i,array[i]);
		}
		return nums;
	}

	/**
	 * Casts an ArrayList of numbers to a float array
	 * @param nums
	 * @return
	 */
	public static float[] floatArray(ArrayList<Number> nums){
		float[] floats = new float[nums.size()];
		for(int i = 0; i<nums.size();i++){
			floats[i] = nums.get(i).floatValue();
		}
		return floats;
	}
	/**
	 * Casts a float array into an arraylist of numbers
	 * @param array
	 * @return
	 */
	public static ArrayList<Number> floatArrayList(float... array){
		ArrayList<Number> nums = new ArrayList<Number>(0);
		for(int i = 0; i<array.length;i++){
			nums.add(i,array[i]);
		}
		return nums;
	}

	/**
	 * Casts an ArrayList of numbers to a byte array
	 * @param nums
	 * @return
	 */
	public static byte[] byteArray(ArrayList<Number> nums){
		byte[] bytes = new byte[nums.size()];
		for(int i = 0; i<nums.size();i++){
			bytes[i] = nums.get(i).byteValue();
		}
		return bytes;
	}
	/**
	 * Casts a byte array into an arraylist of numbers
	 * @param array
	 * @return
	 */
	public static ArrayList<Number> byteArrayList(byte... array){
		ArrayList<Number> nums = new ArrayList<Number>(0);
		for(int i = 0; i<array.length;i++){
			nums.add(i,array[i]);
		}
		return nums;
	}

	/**
	 * Converts an array of objects into an ArrayList
	 * @param <E>
	 * @param array
	 * @return
	 */
	public static <E> ArrayList<E> ArrayList(E... array){
		ArrayList<E> arr = new ArrayList<E>(0);
		for(int i = 0; i<array.length;i++){
			arr.add(i,array[i]);
		}
		return arr;
	}

	/**
	 * Casts an ArrayList into an Array of the same type.
	 * @param <E>
	 * @param e
	 * @param e2
	 * @return The new array
	 */
	public static <E> E[] Array(ArrayList<E> e){
		//return e.toArray( Array( e.get(0) ) );
		E e1 = e.get(0);
		E[] e2 =(E[])Array.newInstance(e1.getClass(), 1);
		E[] array = e.toArray(e2);

		return array;
	}

	/**
	 * Casts an object[] array into the type of your choice
	 * @param <E>
	 * @param array
	 * @param type
	 * @return
	 */
	public static <E> ArrayList<E> cast(Object[] array, E type){
		ArrayList<E> e= new ArrayList<E>();
		for(int i = 0; i<array.length;i++){
			e.add((E)array[i]);
		}
		return e;
	}

	/**
	 * Casts an ArrayList of one type to an ArrayList of another type. Uses an unchecked cast, so errors may pop up at runtime.
	 * @param <V>
	 * @param <E>
	 * @param array
	 * @param type
	 * @return
	 */
	public static <U, V> ArrayList<V> cast(ArrayList<U> array, V type){
		ArrayList<V> e= new ArrayList<V>();
		for(int i = 0; i<array.size();i++){
			e.add((V)array.get(i));
		}
		return e;
	}


	/*
	 * MATH FUNCTIONS
	 *
	 */

	/**
	 * Determines whether an integer is prime or not. NEEDS A SPEED OPTIMIZATION
	 * @param i
	 */
	 public static boolean isPrime(int i)
	    {
	    	if(i<=1)return false;
	    	if(i==2 || i==3) return true;
	    	int limit = (int) java.lang.Math.ceil(java.lang.Math.sqrt( i) );
	    	for(int j = 3; j< limit ;j= j+2) {
	    		if((i%j)!=0) return false;
	    	}
	    	return true;
	    }

	 /**
	  * Returns a frational approximation of the decimal provided.  NEEDS A SPEED OPTIMIZATION.
	  * <BR>
	  * Accuracy is DECENT but not GREAT. This function tries to generate "easy-for-humans" fractional approximations.
	  * <BR><BR>
	  * Examples:
	  * <BR>
	  * frac(Math.PI) >>> 22/7
	  * <BR>
	  * frac(Math.E) >>> 109/32
	  * <BR>
	  * frac(0.1666) >>> 1/6
	  * <BR>
	  * frac(0.25) >>> 1/4
	  * @param dec The decimal to be converted
	  * @return An array in which the 0th element contains the numerator and the 1st element contains the denominator
	  */
	 public static int[] frac(double dec){
		 String s = Double.toString(dec);
		 int places = s.length()- (s.indexOf('.')+1);
		 if(places<2)places = 2;//minimum 100 loops
		 int loops = (int)(Math.pow(10,places)-1);
		 //println("loops requested from ",s," :", loops);
		 return frac(dec, loops);

	 }
	 private static int[] frac(double dec, int loops){
		 if(loops>999)loops=999;//max 999 loops
		 int sign = 1;
		double numer = 1;double denom = 1;
		 if (dec<0) sign=-1;  dec = Math.abs(dec);
		 double bestscore = 10000;double finalnum = 1; double finalden = 1;
		 for(int i = 0; i<loops;i++){
			 denom = i;
			 numer = Math.round(dec*denom);
			 double fracvalue = numer/denom;
			 double err = Math.abs(dec- (fracvalue));
			  double score = ((numer+denom)/500)+ 450*err;// Score calculates the "best fraction" based on size of numer+denom and
			 if(score < bestscore){
				 finalnum = numer;
				 finalden = denom;
				 bestscore = score;
			 }
		 }
		 int n = (int)(finalnum); int d = (int)finalden; int gcd = gcd(n,d);
		 return intArray(sign*n/gcd, d/gcd);
	 }

	 /**
	  * Returns the Greatest Common Divisor (GCD) between two integers using the binary GCD method.
	  * <BR>
	  * <a href= "http://introcs.cs.princeton.edu/java/23recursion/BinaryGCD.java.html">See here for source of method.</a>
	  * @param p 1st number
	  * @param q 2nd number
	  * @return the GCD between p and q
	  */
	 public static int gcd(int p, int q) {
	        if (q == 0) return p;
	        if (p == 0) return q;
	        // p and q even
	        if ((p & 1) == 0 && (q & 1) == 0) return gcd(p >> 1, q >> 1) << 1;
	        // p is even, q is odd
	        else if ((p & 1) == 0) return gcd(p >> 1, q);
	        // p is odd, q is even
	        else if ((q & 1) == 0) return gcd(p, q >> 1);
	        // p and q odd, p >= q
	        else if (p >= q) return gcd((p-q) >> 1, q);
	        // p and q odd, p < q
	        else return gcd(p, (q-p) >> 1);
	    }
	 /**
	  * Returns the Lowest Common Multiple (LCM) between two integers
	  * @param a
	  * @param b
	  * @return LCM
	  */
	 public static int lcm(int a, int b){
		 return (a*b)/gcd(a,b);
	 }

	 /**
	  * Returns the maximum value in the given array. Linear search, O(n) runtime
	  * <br>
	  * O(n) runtime
	  * @param nums
	  * @return max value in the array OR Long.MIN_VALUE if empty array
	  */
	 public static Number max(Number... nums){
		Number max = Long.MIN_VALUE;
		for(int i = 0;i<nums.length;i++){
			if(nums[i].doubleValue()>max.doubleValue()) max=nums[i];
		}
		return max;
	 }
	 /**
	  * Returns the maximum value in the given array.  Linear search, O(n) runtime
	  * <br>
	  * O(n) runtime
	  * @param nums
	  * @return max value in the array OR Long.MIN_VALUE if empty array
	  */
	 public static Number max(ArrayList<Number> nums){
		Number max = Long.MIN_VALUE;
		for(int i = 0;i<nums.size();i++){
			if(nums.get(i).doubleValue()>max.doubleValue()) max=nums.get(i);
		}
		return max;
	 }

	 /**
	  * Returns the minimum value in the given array.  Linear search, O(n) runtime
	  * <br>
	  * O(n) runtime
	  * @param nums
	  * @return min value in the array OR Long.MAX_VALUE if empty array
	  */
	 public static Number min(Number... nums){
			Number min = Long.MAX_VALUE;
			for(int i = 0;i<nums.length;i++){
				if(nums[i].doubleValue()<min.doubleValue()) min=nums[i];
			}
			return min;
		 }
	 /**
	  * Returns the minimum value in the given array.  Linear search, O(n) runtime
	  * <br>
	  * O(n) runtime
	  * @param nums
	  * @return min value in the array OR Long.MAX_VALUE if empty array
	  */
	 public static Number min(ArrayList<Number> nums){
			Number min = Long.MAX_VALUE;
			for(int i = 0;i<nums.size();i++){
				if(nums.get(i).doubleValue()<min.doubleValue()) min=nums.get(i);
			}
			return min;
		 }

	 /**
	  * Floors the specified double at any precision
	  * <br><br>
	  * For example floor(-2.12599,3) = -2.126
	  * @param d
	  * @param precision
	  * @return
	  */
	 public static double floor(double d, int precision){
		 	BigDecimal bd = new BigDecimal(d);
		    bd = bd.setScale(precision, BigDecimal.ROUND_FLOOR);
		    return bd.doubleValue();
	 }
	 /**
	  * Rounds the specified double at any precision
	  * <br><br>
	  * For example round(-2.12599,3) = -2.126
	  * @param d
	  * @param precision
	  * @return
	  */
	 public static double round(double d, int precision){
		 	BigDecimal bd = new BigDecimal(d);
		    bd = bd.setScale(precision, BigDecimal.ROUND_HALF_UP);
		    return bd.doubleValue();
	 }
	 /**
	  * Ceils the specified double at any precision
	  * <br><br>
	  * For example floor(-2.12599,3) = -2.125
	  * @param d
	  * @param precision
	  * @return
	  */
	 public static double ceil(double d, int precision){
		 	BigDecimal bd = new BigDecimal(d);
		    bd = bd.setScale(precision, BigDecimal.ROUND_CEILING);
		    return bd.doubleValue();
	 }
	 /**
	  * Truncates a double to the given decimal place.
	  * <BR>
	  * ! NOT ROUNDING OR CEILING OR FLOORING!
	  * <BR><BR>
	  * For example, truncate(-22.12566,2) yields -22.12
	  * @param d
	  * @param precision
	  * @return
	  */
	 public static double trunc(double d, int precision){
		 int pow = (int) Math.pow(10, precision);
		 int i = (int) (d*pow);
		 return (double)i/pow;
	 }

	/**
	 * Converts radians to degrees
	 * @param radians
	 * @return
	 */
	public static double toDeg(double radians){
		return radians*_180OVERPI;
	}
	/**
	 * Converts radians to degrees
	 * @param radians
	 * @return
	 */
	public static float toDeg(float radians){
		return radians*57.2957795130823208768f;
	}
	/**
	 * Converts degrees to radians
	 * @param degrees
	 * @return
	 */
	public static double toRad(double degrees){
		return degrees*_PIOVER180;
	}
	/**
	 * Converts degrees to radians
	 * @param degrees
	 * @return
	 */
	public static float toRad(float degrees){
		return degrees*0.017453292519943295769f;
	}


	/*
	 * LIST/SORTING/SEARCHING FUNCTIONS
	 */

	/**
	 * An easy way to create integer arrays.
	 * @param nums
	 * @return
	 */
	public static int[] intArray(int... nums){
		return nums;
	}
	/**
	 * An easy way to create byte arrays.
	 * @param nums
	 * @return
	 */
	public static byte[] byteArray(byte... nums){
		return nums;
	}
	/**
	 * An easy way to create double arrays.
	 * @param nums
	 * @return
	 */
	public static double[] doubleArray(double... nums){
		return nums;
	}
	/**
	 * An easy way to create char arrays.
	 * @param chars
	 * @return
	 */
	public static char[] charArray(char... chars){
		return chars;
	}
	/**
	 * An easy way to create float arrays.
	 * @param nums
	 * @return
	 */
	public static float[] floatArray(float... nums){
		return nums;
	}
	/**
	 * An easy way to create generic arrays. For use with all OBJECTS, but not primitive types.
	 * <BR>
	 * For primitives, use their respective method. Ex. intArray() is used for integers.
	 * <BR><BR>
	 * <B>THIS IS SO HACKS.</B> You can create a generic array using this method.
	 * @param <E>
	 * @param e
	 * @return
	 */
	public static <E> E[] Array(E... e){
		E[] array=(E[])Array.newInstance(e[0].getClass(), e.length);
		for(int i = 0; i< array.length; i++){
			array[i] = e[i];
		}
		return array;
	}

	/**
	 * Concatenates the two arrays.
	 * @param <E>
	 * @param e1 first array
	 * @param e2 second array
	 * @return first array+second array.
	 */
	public static <E> E[] concat(E[] e1, E[] e2){
		E[] newE =(E[])Array.newInstance(e1[0].getClass(), e1.length+e2.length);
		for(int i = 0; i<e1.length;i++){
			newE[i] = e1[i];
		}
		for(int i = e1.length; i<newE.length;i++){
			newE[i] = e2[i-e1.length];
		}
		return newE;
	}
	/**
	 * Appends a value to the end of an array
	 * @param e1 array
	 * @param e element to append
	 * @return first array+e.
	 */
	public static <E> E[] add(E[] e1, E e){
		E[] newE =(E[])Array.newInstance(e.getClass(), e1.length+1);
		for(int i = 0; i<e1.length;i++){
			newE[i] = e1[i];
		}
		newE[newE.length-1] = e;
		return newE;
	}

	public static <E> E[] rmv( E[] arr, int index){
		assert(arr.length!=0);
		E[] newE =(E[])Array.newInstance(arr[0].getClass(), arr.length-1);
		for(int i = 0; i<arr.length;i++){
			newE[i] = arr[i];
			if( i == index)
				i = i-1;
		}
		return newE;
	}


	public static <E> ArrayList<E> concat(ArrayList<E> e1, ArrayList<E> e2){
		ArrayList<E> newE = new ArrayList<E>();
		for(int i = 0; i<e1.size();i++){
			newE.add( e1.get(i));
		}
		for(int i = e1.size(); i<e2.size();i++){
			newE.add( e2.get(i));
		}
		return newE;
	}

	/**
	 * A versatile function that creates arrays containing arithmetic series. The variable "n" must be used in defining functions. The series starts at 0 and ends based on the number of iterations you specify.
	 * <BR><BR>
	 * <B>Examples: </B>
	 * <BR>range( "n*2", 9) will generate the array {0,2,4,6,8,10,12,14,16,18}
	 * <BR>range("n*n",5) will generate the array {0.0,1.0,4.0,9.0,16.0,25.0}
	 * <BR><BR>
	 * @param func the function that defines the series
	 * @param iterations the length of the progression."n" starts at 0 and ends at this value.
	 * @return the generated array
	 */
	public static double[] range(String func, int iterations){
		return range(func,0,iterations);
	}
	/**
	 * A versatile function that creates arrays containing arithmetic series. The variable "n" must be used in defining functions.
	 * <BR><BR>
	 * <B>Examples: </B>
	 * <BR>range( "n*2", 0,9) will generate the array {0,2,4,6,8,10,12,14,16,18}
	 * <BR>range("n*n",2,5) will generate the array {4,9,16,25}
	 * <BR><BR>
	 * @param func the function that defines the series
	 * @param nstart the starting value of the progression. "n" will begin with this value
	 * @param nstop the ending value of the progression."n" will end with this value
	 * @return the generated array
	 */
	public static double[] range(String func, int nstart, int nstop){
		nstop++;
		double[] vals = new double[nstop-nstart];
		for(int i = nstart; i<(nstop);i++){
			eval("n="+i);
			double val = (java.lang.Double) eval(func);
			vals[i-nstart]=val;
		}
		return vals;
	}

	/**
	 * A versatile function that creates arrays containing arithmetic series. The variable "n" must be used in defining functions.
	 * <BR><BR>
	 * <B>Examples: </B>
	 * <BR>range( "n*2", 0,9,1) will generate the array {0,2,4,6,8,10,12,14,16,18}
	 * <BR>range("n*n",2,6,2) will generate the array {4,16,36}
	 * <BR><BR>
	 * Take that Python, this range function is so much better!!!
	 * @param func the function that defines the series
	 * @param nstart the starting value of the progression. "n" will begin with this value
	 * @param nstop the ending value of the progression."n" will end with this value
	 * @param nstep the amount "n" increases in value with each iteration.
	 * @return the generated array
	 */
	public static double[] range(String func, int nstart, int nstop,int nstep){
		double[] vals = new double[((nstop-nstart)/nstep)+1];
		nstop++;
		for(int i = nstart; i<(nstop);i+=nstep){
			eval("n="+i);
			double val = (java.lang.Double) eval(func);
			vals[(i-nstart)/nstep]=val;
		}
		return vals;
	}

	/**
	 * Returns the number of occurences of an object inside an array
	 * @param obj the object to look for
	 * @param array the array to look in
	 * @return number of occurences
	 */
	public static <E> int count(E obj, E... array){
		int counter = 0;
		for(int i = 0; i<array.length;i++){
			if(obj == array[i]) counter++;
		}
		return counter;
	}
	/**
	 * Returns the number of occurences of an object inside an array
	 * @param obj the object to look for
	 * @param array the array to look in
	 * @return number of occurences
	 */
	public static <E> int count(E obj, ArrayList<E> array){
		int counter = 0;
		for(int i = 0; i<array.size();i++){
			if(obj == array.get(i)) counter++;
		}
		return counter;
	}

	//search modes
	public final static int _LINEAR = 1;
	public final static int _BINARY = 2;
	private static int searchmode = _LINEAR; //default searcher is linear

	/**
	 * NOT IMPLEMENTED YET. ALL SEARCHES ARE LINEAR
	 * <BR><BR>
	 * Lets you set the algorithm used in the indexOf() methods.
	 * @param mode
	 */
	public static void setSearchMode(int mode){
		searchmode = mode;
	}
	/**
	 * Linear search for the given object inside the array. Returns the index if found, or -1 if not found
	 * @param <E>E:The type of object the list contains
	 * @param o object to look for
	 * @param objs array to look inside
	 * @return the first position that the given object is found at or -1
	 */
	public static <E> int indexOf(E o, ArrayList<E> objs){
		for(int i = 0; i<objs.size();i++){
			if(o.equals(objs.get(i)))return i;
		}
		return -1;
	}
	/**
	 * Linear search for the given object inside the array. Returns the index if found, or -1 if not found
	 * @param o object to look for
	 * @param startindex the index to start the search at
	 * @param objs array to look inside
	 * @return the first position that the given object is found at or -1
	 */
	public static <E> int indexOf(E o, int startindex, ArrayList<E> objs){
		for(int i = startindex; i<objs.size();i++){
			if(o.equals(objs.get(i)))return i;
		}
		return -1;
	}
	/**
	 * Linear search for the given object inside the array. Returns the index if found, or -1 if not found
	 * @param <E>E:The type of object the list contains
	 * @param o object to look for
	 * @param objs array to look inside
	 * @return the first position that the given object is found at or -1
	 */
	public static <E> int indexOf(E o, E[] objs){
		for(int i = 0; i<objs.length;i++){
			if(o.equals(objs[i]))return i;
		}
		return -1;
	}
	/**
	 * Linear search for the given object inside the array. Returns the index if found, or -1 if not found
	 * @param o object to look for
	 * @param startindex the index to start the search at
	 * @param objs array to look inside
	 * @return the first position that the given object is found at or -1
	 */
	public static <E> int indexOf(E o, int startindex, E[] objs){
		for(int i = startindex; i<objs.length;i++){
			if(o.equals(objs[i]))return i;
		}
		return -1;
	}

	//sort modes
	/**
	 * Will use quicksort by defualt
	 */
	public final static int _QUICK = 50;
	/**
	 * NOTE: TimSort is currently very slow for primitives... Needs to go through an extra O(2n) of time.
	 */
	private static int sortmode = _QUICK;//default sorter is quicksort

	/**
	 * Lets you set the algorithm used in the sort() and hashsort() methods.
	 * @param mode
	 */
	public static void setSortMode(int mode){
		sortmode = mode;
	}
	/**
	 * Sorts an integer array from least to greatest.
	  * <BR><BR>
	  * !WARNING! This method may modify the array you pass as a parameter. Make a copy of the array if you wish to keep the original.
	 * @param intArray
	 * @return the sorted array (Optional, as the passed array is also modified)
	 */
	public static int[] sort(int[] intArray){
		QuickSort.sort(intArray);
		return intArray;
	}
	/**
	 * Sorts a double array from least to greatest.
	 *  <BR><BR>
	 * !WARNING! This method may modify the array you pass as a parameter. Make a copy of the array if you wish to keep the original.
	 * @param dblArray
	 * @return the sorted array (Optional, as the passed array is also modified)
	 */
	public static double[] sort(double... dblArray){
		QuickSort.sort(dblArray);
		return dblArray;
	}
	/**
	 * Sorts a number array from least to greatest.
	 * <BR>
	 * <B>All numbers must be less than the max value for doubles</B>, as this method converts the numbers to doubles in order to compare.
	  * <BR><BR>
	  * !WARNING! This method may modify the array you pass as a parameter. Make a copy of the array if you wish to keep the original.
	 * @param numArray
	 * @return the sorted array (Optional, as the passed array is also modified)
	 */
	public static ArrayList<Number> sort(ArrayList<Number> numArray){
		QuickSort.sort(numArray);
		return numArray;
	}
	/**
	 * Sorts a number array form least to greatest by hashcode.
	 * <BR><BR>
	 *  !WARNING! This method may modify the array you pass as a parameter. Make a copy of the array if you wish to keep the original.
	 * @param numArray
	 * @return the sorted array
	 */
	public static <E> java.util.ArrayList<E> hashsort(ArrayList<E> array){
		return QuickSort.hashsort(array);
	}

	/*
	 * REFLECTION HELPERS
	 */

	/**
	 * Invokes a method on an object via reflection. Will work regardless of private/protected modifiers
	 * @param o the object being invoked on
	 * @param methodname the name of the method to be run
	 * @param args parameters for that method
	 * @return the return value of the method
	 */
	public static Object invoke(Object o, String methodname, Object...args) {
		try{
		Class<? extends Object> c = o.getClass();
		//get the parametertypes
		Class[] parameterTypes = new Class[args.length];
		for(int i = 0;i<parameterTypes.length;i++){
			parameterTypes[i] = args[i].getClass();
		}
		Method m = c.getDeclaredMethod(methodname, parameterTypes);
		m.setAccessible(true);
		return m.invoke(o, args);
		}
		catch(Exception e){e.printStackTrace(); return null;}
	}

	/**
	 * Changes the field on an object. Will work regardless of final/private/protected/etc modifiers.
	 * <BR>
	 * Yes, you can change private final static variables.
	 * @param o the object containing the field
	 * @param fieldname the name of the field
	 * @param value the field's new value
	 */
	public static void setField(Object o, String fieldname, Object value){
		try{
		Class<? extends Object> c = o.getClass();
		Field f = c.getDeclaredField(fieldname);
		f.setAccessible(true);
		f.set(o, value);
		}
		catch(Exception e){e.printStackTrace(); return;}
	}

}

/**
 * <a href= "http://www.vogella.de/articles/JavaAlgorithmsQuicksort/article.html">Code copied from here</a>
 * @author Lars Vogel at <a href= "http://www.vogella.de/articles/JavaAlgorithmsQuicksort/article.html">www.vogella.de/articles/JavaAlgorithmsQuicksort/article.html</a>
 *
 */
class QuickSort  {

	/*
	 * INTEGER SORT
	 */

	public static int[] sort(int[] values) {
		// Check for empty or null array
		if (values ==null || values.length==0){
			return null;
		}
		//number = values.length;
		return quicksort(values, 0, values.length - 1);
	}

	private static int[] quicksort(int[] nums, int low, int high) {
		int i = low, j = high;
		// Get the pivot element from the middle of the list
		int pivot = nums[low + (high-low)/2];

		// Divide into two lists
		while (i <= j) {
			// If the current value from the left list is smaller then the pivot
			// element then get the next element from the left list
			while (nums[i] < pivot) {
				i++;
			}
			// If the current value from the right list is larger then the pivot
			// element then get the next element from the right list
			while (nums[j] > pivot) {
				j--;
			}

			// If we have found a values in the left list which is larger then
			// the pivot element and if we have found a value in the right list
			// which is smaller then the pivot element then we exchange the
			// values.
			// As we are done we can increase i and j
			if (i <= j) {
				exchange(nums, i, j);
				i++;
				j--;
			}
		}
		// Recursion
		if (low < j)
			quicksort(nums, low, j);
		if (i < high)
			quicksort(nums, i, high);

		return nums;
	}

	private static void exchange(int[] nums, int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}


	/*
	 * DOUBLES SORT
	 */


	public static double[] sort(double[] values) {
		// Check for empty or null array
		if (values ==null || values.length==0){
			return null;
		}
		//number = values.length;
		return quicksort(values, 0, values.length - 1);
	}

	private static double[] quicksort(double[] nums, int low, int high) {
		int i = low, j = high;
		// Get the pivot element from the middle of the list
		double pivot = nums[low + (high-low)/2];

		// Divide into two lists
		while (i <= j) {
			// If the current value from the left list is smaller then the pivot
			// element then get the next element from the left list
			while (nums[i] < pivot) {
				i++;
			}
			// If the current value from the right list is larger then the pivot
			// element then get the next element from the right list
			while (nums[j] > pivot) {
				j--;
			}

			// If we have found a values in the left list which is larger then
			// the pivot element and if we have found a value in the right list
			// which is smaller then the pivot element then we exchange the
			// values.
			// As we are done we can increase i and j
			if (i <= j) {
				exchange(nums, i, j);
				i++;
				j--;
			}
		}
		// Recursion
		if (low < j)
			quicksort(nums, low, j);
		if (i < high)
			quicksort(nums, i, high);

		return nums;
	}

	private static void exchange(double[] nums, int i, int j) {
		double temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}

	/*
	 * For Arraylists
	 */

	public static java.util.ArrayList<Number> sort(java.util.ArrayList<Number> values) {
		// Check for empty or null array
		if (values ==null || values.size()==0){
			return null;
		}
		//number = values.length;
		return quicksort(values, 0, values.size() - 1);
	}

	private static java.util.ArrayList<Number> quicksort(java.util.ArrayList<Number> nums, int low, int high) {
		int i = low, j = high;
		// Get the pivot element from the middle of the list
		double pivot = nums.get(low + (high-low)/2).doubleValue();

		// Divide into two lists
		while (i <= j) {
			// If the current value from the left list is smaller then the pivot
			// element then get the next element from the left list
			while (nums.get(i).doubleValue() < pivot) {
				i++;
			}
			// If the current value from the right list is larger then the pivot
			// element then get the next element from the right list
			while (nums.get(j).doubleValue() > pivot) {
				j--;
			}

			// If we have found a values in the left list which is larger then
			// the pivot element and if we have found a value in the right list
			// which is smaller then the pivot element then we exchange the
			// values.
			// As we are done we can increase i and j
			if (i <= j) {
				exchange(nums, i, j);
				i++;
				j--;
			}
		}
		// Recursion
		if (low < j)
			quicksort(nums, low, j);
		if (i < high)
			quicksort(nums, i, high);

		return nums;
	}

	private static void exchange(java.util.ArrayList<Number> nums, int i, int j) {
		Number temp = nums.get(i);
		nums.set(i,nums.get(j));
		nums.set(j, temp);
	}

	/*
	 * For Objects using hashcodes
	 */

	public static <E> java.util.ArrayList<E> hashsort(java.util.ArrayList<E> values) {
		// Check for empty or null array
		if (values ==null || values.size()==0){
			return null;
		}
		//number = values.length;
		return hashquicksort(values, 0, values.size() - 1);
	}

	private static <E> java.util.ArrayList<E> hashquicksort(java.util.ArrayList<E> nums, int low, int high) {
		int i = low, j = high;
		// Get the pivot element from the middle of the list
		double pivot = nums.get(low + (high-low)/2).hashCode();

		// Divide into two lists
		while (i <= j) {
			// If the current value from the left list is smaller then the pivot
			// element then get the next element from the left list
			while (nums.get(i).hashCode() < pivot) {
				i++;
			}
			// If the current value from the right list is larger then the pivot
			// element then get the next element from the right list
			while (nums.get(j).hashCode() > pivot) {
				j--;
			}

			// If we have found a values in the left list which is larger then
			// the pivot element and if we have found a value in the right list
			// which is smaller then the pivot element then we exchange the
			// values.
			// As we are done we can increase i and j
			if (i <= j) {
				hashexchange(nums, i, j);
				i++;
				j--;
			}
		}
		// Recursion
		if (low < j)
			hashquicksort(nums, low, j);
		if (i < high)
			hashquicksort(nums, i, high);

		return nums;
	}

	private static <E> void hashexchange(java.util.ArrayList<E> nums, int i, int j) {
		E temp = nums.get(i);
		nums.set(i,nums.get(j));
		nums.set(j, temp);
	}

}
